﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Collections;
using UnityEngine;
using UnityEngine.UI;

namespace Z1029.NoteGlobalView
{
    public class LevelController : MonoBehaviour
    {
        [Header("Edit")]
        public bool Play;
        public float NowTime;
        public int NowBeatTime;
        public float TimeScale;
        [Header("Init Settings")]
        [NonSerialized]
        public string chart;
        public AudioClip music;

        public Sprite illustration, illustrationBlur;
        public Transform m_level;
        public string musicName, levelInfo, levelHarder;
        public SpriteRenderer background;
        public GameObject judgelinePrefab;
        public List<JudgementLine> judgelines;
        public Transform progressBar;
        public Text musicNameText;
        public Text comboShow;
        public Text scoreText;
        public Text musicNameInInfo;
        public Text harderText;
        public Text levelInfoText;
        public NotesManager notesManager;
        public HitEffectManager hitEffectManager;
        public int combo;
        public float score;
        public int notesCount;
        public static LevelController instance;
        private float musicLength => music.length;
        public AudioSource musicSource;
        public static double nowTime;
        public Chart gameChart;
        public Note[] notes;
        int maxCombo;
        public int comboScore;
        public float startTime;

        public LoadState loadState;

        public static float noteSize = 0.26f;
        public static float hitSoundsVolume = 0.6f;
        public static double musicOffset;

        static bool WantsToQuit()
        {
            Application.Quit();
            return true;
        }

        private void Awake()
        {
            int val = PlayerPrefs.GetInt("DspBuffer", 512);
            AudioSettings.SetDSPBufferSize(val, val);
            Application.wantsToQuit += WantsToQuit;
            Application.targetFrameRate = 90;
            LevelController.instance = this;
            
            string path = Path.Combine(Path.GetDirectoryName(Application.dataPath), "Project//music.wav");
            StartCoroutine(LoadMusic(path));
            musicSource = m_level.GetComponent<AudioSource>();
            musicNameText.text = musicName;
            musicNameInInfo.text = musicName;
            levelInfoText.text = string.Format("Illustration designed by {0}\nLevel designed by {1}", levelInfo.Split(',')[0], levelInfo.Split(',')[1]);
            harderText.text = levelHarder;
            Screen.SetResolution(1920, 1080, true);
            FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read);
            byte[] bytes = new byte[fs.Length];
            illustrationBlur = GetSprite(Path.Combine(Path.GetDirectoryName(Application.dataPath), "Project//illustration.png"));
            background.sprite = illustrationBlur;
            path = Path.Combine(Path.GetDirectoryName(Application.dataPath), "Project//Chart.json");
            fs = new FileStream(path, FileMode.Open, FileAccess.Read);
            bytes = new byte[fs.Length];
            fs.Read(bytes, 0, (int)fs.Length);
            fs.Close();
            //enabled = false;
            path = Path.Combine(Path.GetDirectoryName(Application.dataPath), "Project//Chart_TMP.json");
            if (File.Exists(path))
            {
                gameChart = JsonUtility.FromJson<Chart>(File.ReadAllText(path, Encoding.UTF8));
                File.Delete(path);
            }
            else
            {
                chart = Encoding.UTF8.GetString(bytes);
                LoadChart(chart);
            }
            NowBeatTime = Utils.GetBeatTimeFromTime(nowTime, gameChart.judgeLineList[0].bpm);
        }
        

        public Sprite GetSprite(string path)
        {
            FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read);
            byte[] bytes = new byte[fs.Length];
            fs.Read(bytes, 0, (int)fs.Length);
            int width = 512;
            int height = 270;
            Texture2D t2d = new Texture2D(width, height);
            t2d.LoadImage(bytes);
            Sprite sp = Sprite.Create(t2d, new Rect(0, 0, t2d.width, t2d.height), new Vector2(0.5f, 0.5f));
            return sp;
        }

        public IEnumerator LoadMusic(string path)
        {

            //path = Application.dataPath + "Project//music.ogg";
            path = "file:///" + path;
            WWW www = new WWW(path);
            yield return www;
            if (www.error == null)
            {
                music = www.GetAudioClip();
                musicSource.clip = music;
            }
            else
            {
                Debug.LogError(www.error);
                Application.Quit();
#if UNITY_EDITOR
                UnityEditor.EditorApplication.isPlaying = false;
#endif
            }

        }

        private void LoadChart(string chart)
        {
            //gameChart = ChartReader.ReadChart(chart);//JsonUtility.FromJson<Chart>(chart);//JsonMapper.ToObject<Chart>(chart);//JsonConvert.DeserializeObject<LevelController.Chart>(chart);
            gameChart = PhigrosChartReader.ReadChart(chart);
        }

        private void Start()
        {
            SetJudgeLines();
            SetNotes();
            if (loadState== LoadState.LoadTmp) ChartFormater.Save();
            if (loadState== LoadState.ReloadToEditor) ChartFormater.Save();
        }

        public InputField createLineBpm;

        public void InitBpmText()
        {
            createLineBpm.text = gameChart.judgeLineList[0].bpm.ToString();
        }

        public void CreateJudgeline()
        {
            Transform lineObj = Instantiate(judgelinePrefab.transform);
            JudgementLine line = lineObj.GetComponent<JudgementLine>();
            lineObj.parent = m_level;
            line.index = FindObjectsOfType<JudgementLine>().Length;
            line.bpm = float.Parse(createLineBpm.text);
            line.speeds = new SpeedEvent[1];
            line.moveEvents = new List<ValueSet>();
            line.rotateEvents = new List<ValueSet>();
            line.alphaEvents = new List<ValueSet>();
            line.transform.localPosition = Vector3.zero;
            judgelines.Add(line);
        }

        public InputField selectIndex;
        

        public void SelectIndexJudgeline()
        {
            JudgementLine.selectedJudgeline = judgelines[int.Parse(selectIndex.text)];
        }

        private void Update()
        {
            if (NowBeatTime < 0) NowBeatTime = 0;
            if (Input.GetKeyDown(KeyCode.Space))
            {
                if (JudgementLine.IsEditing)
                    Play = NoteEditor.LevelController.instance.Play;
                else Play = !Play;
            }
            if (Play)
            {
                nowTime += Time.smoothDeltaTime * TimeScale;
                musicSource.pitch = TimeScale;
                NowTime = (float)nowTime;
                NowBeatTime = Utils.GetBeatTimeFromTime(nowTime, judgelines[0].bpm);
                if (!musicSource.isPlaying && !JudgementLine.IsEditing) musicSource.Play();
            }
            else
            {
                if(!JudgementLine.IsEditing)NowBeatTime += (int)(Input.GetAxis("Mouse ScrollWheel") * 75);
                nowTime = Utils.GetTimeFromBeatTime(NowBeatTime, judgelines[0].bpm);
                musicSource.time = (float)nowTime;
                if (musicSource.isPlaying && !JudgementLine.IsEditing) musicSource.Pause();
            }
            //if (!JudgementLine.IsEditing && musicSource.isPlaying) musicSource.Pause();
            progressBar.localPosition = new Vector3((float)nowTime / musicLength * 1920f - 1920f, progressBar.localPosition.y, progressBar.localPosition.z);
            if (nowTime + 0.1f > musicLength)
            {
                nowTime = musicLength - 0.1f;
                Play = false;
            }
        }

        private void SetJudgeLines()
        {
            judgelines = new List<JudgementLine>();
            for (int i = 0; i < gameChart.judgeLineList.Length; i++)
            {
                judgelines.Add(new JudgementLine());
                Transform lineObj = Instantiate(judgelinePrefab.transform);
                judgelines[i] = lineObj.GetComponent<JudgementLine>();
                lineObj.parent = m_level;
                JudgementLine line = judgelines[i];
                line.index = i;
                line.bpm = gameChart.judgeLineList[i].bpm;
                line.speeds = gameChart.judgeLineList[i].speedEvents;
                line.moveEvents = gameChart.judgeLineList[i].moveEvents;
                line.rotateEvents = gameChart.judgeLineList[i].rotateEvents;
                line.alphaEvents = gameChart.judgeLineList[i].alphaEvents;
                int count = gameChart.judgeLineList[i].notesAbove.Length + gameChart.judgeLineList[i].notesBelow.Length;
            }
            EnableJudgelines(true);
        }

        private void SetNotes()
        {
            notesCount = 0;
            notes = new Note[gameChart.numOfNotes+1000];//防止出错
            for (int i = 0; i < judgelines.Count; i++)
            {
                for (int j = 0; j < gameChart.judgeLineList[i].notesAbove.Length; j++)
                {
                    Note.NoteData data = gameChart.judgeLineList[i].notesAbove[j];
                    data.index = notesCount;
                    notes[notesCount] = notesManager.InstantiateNote(gameChart.judgeLineList[i].notesAbove[j].type, data, judgelines[i], Note.Direction.Above);
                    notesCount++;
                }
                for (int k = 0; k < gameChart.judgeLineList[i].notesBelow.Length; k++)
                {
                    Note.NoteData data = gameChart.judgeLineList[i].notesBelow[k];
                    data.index = notesCount;
                    notes[notesCount] = notesManager.InstantiateNote(gameChart.judgeLineList[i].notesBelow[k].type, data, judgelines[i], Note.Direction.Below);
                    notesCount++;
                }
            }
            if (notesCount != gameChart.numOfNotes) Debug.LogError("ChartReadError!");
        }

        public void Quit()
        {
            Application.Quit();
        }

        public void EnableJudgelines(bool enable)
        {
            for (int i = 0; i < judgelines.Count; i++)
            {

                judgelines[i].enabled = enable;
                judgelines[i].UpdateJudgelineColor();
            }
        }

        public enum LoadState
        {
            Standard,LoadTmp,ReloadToEditor
        }
    }
}